msg_tool\scripts\kirikiri/
mdf.rs1use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use anyhow::Result;
6use std::io::Read;
7
8#[derive(Debug)]
9pub struct MdfBuilder {}
11
12impl MdfBuilder {
13 pub fn new() -> Self {
15 Self {}
16 }
17}
18
19impl ScriptBuilder for MdfBuilder {
20 fn default_encoding(&self) -> Encoding {
21 Encoding::Utf8
22 }
23
24 fn build_script(
25 &self,
26 buf: Vec<u8>,
27 filename: &str,
28 _encoding: Encoding,
29 _archive_encoding: Encoding,
30 _config: &ExtraConfig,
31 _archive: Option<&Box<dyn Script>>,
32 ) -> Result<Box<dyn Script>> {
33 Ok(Box::new(Mdf::new(buf, filename)?))
34 }
35
36 fn extensions(&self) -> &'static [&'static str] {
37 &[]
38 }
39
40 fn script_type(&self) -> &'static ScriptType {
41 &ScriptType::KirikiriMdf
42 }
43
44 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
45 if buf_len >= 4 && buf.starts_with(b"mdf\0") {
46 Some(10)
47 } else {
48 None
49 }
50 }
51}
52
53#[derive(Debug)]
54pub struct Mdf {
56 data: MemReader,
57 ext: String,
58}
59
60impl Mdf {
61 pub fn new(buf: Vec<u8>, filename: &str) -> Result<Self> {
66 let mut data = MemReader::new(buf);
67 let mut header = [0u8; 4];
68 data.read_exact(&mut header)?;
69 if &header != b"mdf\0" {
70 return Err(anyhow::anyhow!("Invalid MDF header"));
71 }
72 Ok(Self {
73 data,
74 ext: std::path::Path::new(filename)
75 .extension()
76 .and_then(|s| s.to_str())
77 .unwrap_or("")
78 .to_string(),
79 })
80 }
81
82 pub(crate) fn unpack(mut data: MemReaderRef) -> Result<Vec<u8>> {
83 let size = data.read_u32()?;
84 let mut decoder = flate2::read::ZlibDecoder::new(data);
85 let mut result = Vec::new();
86 decoder.read_to_end(&mut result)?;
87 if size as usize != result.len() {
88 eprintln!(
89 "Warning: MDF unpacked size mismatch: expected {}, got {}",
90 size,
91 result.len()
92 );
93 crate::COUNTER.inc_warning();
94 }
95 Ok(result)
96 }
97}
98
99impl Script for Mdf {
100 fn default_output_script_type(&self) -> OutputScriptType {
101 OutputScriptType::Custom
102 }
103
104 fn default_format_type(&self) -> FormatOptions {
105 FormatOptions::None
106 }
107
108 fn is_output_supported(&self, output: OutputScriptType) -> bool {
109 matches!(output, OutputScriptType::Custom)
110 }
111
112 fn custom_output_extension<'a>(&'a self) -> &'a str {
113 &self.ext
114 }
115
116 fn custom_export(&self, filename: &std::path::Path, _encoding: Encoding) -> Result<()> {
117 let data = Self::unpack(MemReaderRef::new(&self.data.data[4..]))?;
118 let mut writer = crate::utils::files::write_file(filename)?;
119 writer.write_all(&data)?;
120 Ok(())
121 }
122}